package csv
import sugarbind_input.*
import app.*

class ObjFinder {
	
	DefaultValue d = new DefaultValue()

	//-------------------
	//Biblio
	//-------------------
	
	def findArticleType(String articleTypeName)
	{
		Article_Type.findByArticle_Type_Name(Utils.importFormat(articleTypeName))
	}
	
	def findArticle(String title, String pubYear)
	{
		Article.findByTitleAndPub_Year(Utils.importFormat(title),Utils.importFormat(pubYear))
	}
	
	def findAuthor(String lastName, String firstName, String midName)
	{
		Author.findByLast_NameAndFirst_NameAndMid_Name(Utils.importFormat(lastName),Utils.importFormat(firstName),Utils.importFormat(midName))
	}
	
	
	
	//-------------------
	//Pathogen
	//-------------------
	
	def findAgentType(String agentTypeName)
	{
		Agent_Type.findByAgent_Type_Name(Utils.importFormat(agentTypeName))
	}
	
	//not used!!
	def findAgent(String agentName, Article article)
	{
		def agent
		def agentNames = agentName.split(d.semicolon,-1)
		System.out.println("findAgent : $agentName")
		def name = agentNames[agentNames.length-1]
		if(name.isEmpty() || name == null)
		{
			agent = findAgent(Utils.importFormat(d.UNKNOWN), agentNames[agentNames.length-2], article)
		}
		else
		{
			
			agent = Agent.findByAgent_NameIlike(Utils.importFormat(agentNames[agentNames.length-1]))
		}		
		return agent
	}
	
	def findAgent(String agentName, int agentIndex, Article article)
	{
		
		def agent
		def agentNames = agentName.split(d.semicolon,-1)
		println(agentNames[agentIndex] + " index " + agentIndex + " article" + article)

		if(agentIndex == 0)
		{
				agent = Agent.findByAgent_NameIlike(Utils.importFormat(agentNames[agentIndex]))
				println("agentIndex == 0 / $agent")
		}
		if(agentIndex == 1 )//|| agentIndex < agentNames.size()-1)
		{		
			def parent = findAgent(agentName, agentIndex-1, article) //Agent.findByAgent_Name(Utils.importFormat(agentNames[agentIndex-1]))						
			agent = Agent.findByAgent_NameIlikeAndAgent_Parent(Utils.importFormat(agentNames[agentIndex]), parent)
			println("agentIndex == 1 / $agent")
		}
		if(agentIndex > 1)// && agentIndex == agentNames.size()-1)
		{
			def grandParent = Agent.findByAgent_NameIlike(Utils.importFormat(agentNames[agentIndex-2]))
			def parent = Agent.findByAgent_NameIlikeAndAgent_Parent(Utils.importFormat(agentNames[agentIndex-1]), grandParent)
			
			def agents = Agent.findAllByAgent_NameIlikeAndAgent_Parent(Utils.importFormat(agentNames[agentIndex]), parent)
//			println("agentIndex > 1 / $grandParent / $parent / ${Utils.importFormat(agentNames[agentIndex])}")
//			println("agentIndex > 1 / $agents")
//			println("agentIndex > 1 / $agent")
                        

			//parent = findAgent(agentName, agentIndex-1, article) //
			if(agents.size()==1 && !agentNames[agentIndex].equals(d.UNKNOWN_STRAIN))
			{
                            println("agents.size()==1 " + agentNames[agentIndex])
				agent = Agent.findByAgent_NameIlikeAndAgent_Parent(Utils.importFormat(agentNames[agentIndex]), parent)
			}
                        else if(agentNames[agentIndex].equals(d.UNKNOWN_STRAIN))
			{
                            
                            println(agentNames[agentIndex] + agents.size())
//				println("name : ${Utils.importFormat(agentNames[agentIndex])}/ parent : ${parent} / article ${article.article_Import_Ref}")
//				agent = Agent.findByAgent_NameIlikeAndAgent_ParentAndArticle_Import_Ref(Utils.importFormat(agentNames[agentIndex]), parent, article.article_Import_Ref)
                                agent = findAgent(agentNames[agentIndex],  parent, article)
                            println("agent " + agent)
                            println("agent params : ${Utils.importFormat(agentNames[agentIndex])} /$parent /$article.article_Import_Ref")    
			}
			else
			{
                            
                            println("agents.size()!=1 : " + agents.size())
//				println("name : ${Utils.importFormat(agentNames[agentIndex])}/ parent : ${parent} / article ${article.article_Import_Ref}")
//				agent = Agent.findByAgent_NameIlikeAndAgent_ParentAndArticle_Import_Ref(Utils.importFormat(agentNames[agentIndex]), parent, article.article_Import_Ref)
                                agent = findAgent(agentNames[agentIndex],  parent, article)
                            println("agent " + agent)
                            println("agent params : ${Utils.importFormat(agentNames[agentIndex])} /$parent /$article.article_Import_Ref")    
			}
			println("agentIndex > 1 / $grandParent / $parent / ${Utils.importFormat(agentNames[agentIndex])}")
			println("agentIndex > 1 / $agents / ")// + agents.getClass())
			println("agentIndex > 1 / $agent")
		}
		
		System.out.println("found agent: " + agent)
		return agent
	}
	
	def findAgent(String agentName, Agent parent, Article article)
	{
		println("findAgent(String agentName, Agent parent, Article article) : $agentName $parent $article")
		def agent
		
//		System.out.println("findAgent(3) : $agentName $parentAgentName $article")
//		System.out.println("findAgent(3) : parentAgent $parentAgent ")
		if(article == null)
		{			
			agent = Agent.findByAgent_NameIlikeAndAgent_Parent(agentName, parent)
//			println("findAgent no article $agentName $parentAgent $article")
		}
		else
		{
                        //starting from article, find all bindings -> support -> lectin -> agent
                        def agentsArticle = findAllAgentsFromArticle(article)
                        
                        //def agentsParent = 
                        println("parent : " + parent)
                        
                        for(Agent a : agentsArticle)
                        {
                            if(parent == null)
                            //if(a.agent_Parent == null)
                            {
                                println("test NO parent : ")
                                try
                                {
                                    println(a.agent_Name.toLowerCase() + " =? " 
                                            + agentName.toLowerCase() + " "  
                                            + a.agent_Name.toLowerCase().equals(agentName.toLowerCase())  + "/"
    //                                        + a.agent_Parent.id + "=?" 
    //                                        + parent.id  + " "
    //                                        + a.agent_Parent.id == parent.id
                                            )
                                    if(a.agent_Name.toLowerCase().equals(agentName.toLowerCase()) &&  a.agent_Parent.parent == null)
                                    {
                                     agent = a   
                                     println("test ok : " + agent + "/"+a)
                                    }
                                }
                                catch(Exception ex)
                                {
                                    System.err.println(ex.getMessage())                                    
                                }
                            }    
                            else
                            {
                                println("test parent : ")
                                try
                                {
                                    println(a.agent_Name.toLowerCase() + " =? " 
                                            + agentName.toLowerCase() + " "  
                                            + a.agent_Name.toLowerCase().equals(agentName.toLowerCase())  + "/"
                                            + a.agent_Parent.id + "=?" 
                                            + parent.id  + " "
                                            + a.agent_Parent.id == parent.id
                                            )
                                    if(a.agent_Name.toLowerCase().equals(agentName.toLowerCase()) && a.agent_Parent.id == parent.id)
                                    {
                                     agent = a   
                                     println("test ok : " + agent + "/"+a)
                                    }
                                } 
                                catch(Exception ex)
                                {
                                    System.err.println(ex.getMessage())
                                }
                            }
                            
                        }
			//agent = Agent.findByAgent_NameIlikeAndAgent_ParentAndArticle_Import_Ref(agentName, parent, article.article_Import_Ref)
//			println("findAgent with article $agentName $parentAgent $article")
		}
		println("findAgent : agent $agent")
		return agent
	}
	
        def findAllAgentsFromArticle(Article article)
        {
            List<Agent> agents = new ArrayList<Agent>()
            println("agents from article "+agents.size()+ " " + article)
            def bindings = article.bindings
            for(Binding binding : bindings)
            {
//                try{
                def agent = binding.lectin.lectin_Support.agent
//                println("from article : " + agent)
                agents.add(agent)
                if(agent.agent_Parent!=null)
                {
                    agents.add(agent.agent_Parent)
                }    
//                }
//                catch(Exception ex)
//                {
//                   System.err.println(ex.getMessage())
//                }
            }
            println("agents from article "+agents.size()+ " " + article)
            println("agents from article "+agents)
            return agents
        }
    
	def findAgent(String agentName, String parentAgentName, Article article)
	{		
		println("findAgent : $agentName $parentAgentName $article")
//		System.out.println("findAgent(3) : $agentName $parentAgentName $article")
//		System.out.println("findAgent(3) : parentAgent $parentAgent ")
		if(article == null)
		{			
			agent = Agent.findByAgent_NameIlikeAndAgent_Parent(agentName, Agent.findByAgent_NameIlike(parentAgentName))
//			println("findAgent no article $agentName $parentAgent $article")
		}
		else
		{
			agent = Agent.findByAgent_NameIlikeAndAgent_ParentAndArticle_Import_Ref(agentName, Agent.findByAgent_NameIlike(parentAgentName), article.article_Import_Ref)
//			println("findAgent with article $agentName $parentAgent $article")
		}
		println("found agent  : $agent")
		return agent
	}
	
	
	def findAgentPropertyType(String agentPropertyTypeName)
	{
		Agent_Property_Type.findByAgent_Property_Type_Name(Utils.importFormat(agentPropertyTypeName))
	}
	
	def findAgentProperty(String agentPropertyValue, Agent_Property_Type agentPropertyType)
	{
		Agent_Property.findByAgent_Property_TypeAndAgent_Property_Value(agentPropertyType, Utils.importFormat(agentPropertyValue))
	}
	
	def findLectinSupportType(String lectinSupportTypeName)
	{
		println("lectin support type finder : $lectinSupportTypeName");
		Lectin_Support_Type.findByLectin_Support_Type_Name(Utils.importFormat(lectinSupportTypeName))
	}
	
	def findLectinSupport(String supportName, Agent agent, Lectin_Support_Type supportType)
	{
		def name = d.UNKNOWN
		if(supportName!=null)
		{
			name = supportName
		}		
//		println("lectin support finder : $supportName $agent $supportName ");
		
		def support = Lectin_Support.findByAgentAndLectin_Support_NameAndLectin_Support_Type(agent,Utils.importFormat(name),supportType)
		
		println("found lectin support : $support");
		return support		
	}
	
	def findLectin(String lectinName, Lectin_Support lectinSupport, Ligand ligand)
	{
		if(lectinName==null || lectinName.isEmpty())
		{
			lectinName=d.UNKNOWN
		}
		
		// find a lectin Not assigned to a binding (the latest created one)
		def lectin = findLectinNoBindings(lectinName, lectinSupport)
		if(lectin==null)
		{
		//else find a lecting assigned to a binding
			lectin=findLectinBindings(lectinName, lectinSupport, ligand)
		}
//		println("findLectin lectin : $lectin")
		return lectin
	}
	
	def findBindings(Ligand ligand, Lectin lectin)
	{
		Binding.findByLigandAndLectin(ligand, lectin)
	}	
	
	def findLectinBindings(String lectinName, Lectin_Support lectinSupport, Ligand ligand)
	{
		Lectin searched = null
//		println("String $lectinName, Agent_Property $agentProperty, Ligand $ligand")
		if(lectinName==null || lectinName.isEmpty())
		{
			lectinName=d.UNKNOWN
		}

		def lectins = Lectin.findAllByLectin_NameAndLectin_Support(Utils.importFormat(lectinName),lectinSupport)
//		println("findLectinBindings lectins : $lectins")
		
		//for each lecting with same name and support
		for(lectin in lectins)
		{
			//get the bindings
			def bindings = lectin.bindings
//			println("findLectinBindings bindings2 : $bindings")
			//if bindings assigned
			if(bindings!=null)
			{
				//for each one
				for(binding in bindings)
				{
//					println("binding.ligand : ${binding.ligand}")
					
					//if the ligand iupac structure of the binding equals the ligand of the current binding
					if(binding.ligand.structure.iupac==ligand.structure.iupac)
					{
//						println("ligand EQUAL: ${binding.ligand.full_Name} ${ligand.full_Name}")
						//the searched lectin aready exist and is returned
						searched = lectin
						return searched
					}
				}
			}
		}
//		println("Lectin WITH bindings : ${searched}")
		return searched
	}
	
	def findLectinNoBindings(String lectinName, Lectin_Support lectinSupport)
	{
		Lectin searched
		if(lectinName==null || lectinName.isEmpty())
		{
			lectinName=d.UNKNOWN
		}
//		System.out.println("findLectin : $lectinName $agentProperty");
		def lectins = Lectin.findAllByLectin_NameAndLectin_Support(Utils.importFormat(lectinName),lectinSupport)
		for(lectin in lectins)
		{
			//get the bindings
			def bindings = lectin.bindings

			//if bindings assigned
			if(bindings==null)
			{
				searched=lectin
			}
		}
		
//		println("findLectinNoBindings lectin : $searched")	
		return searched
	}
	
	def findDisease(String diseaseName)
	{
		Disease.findByDisease_Name(Utils.importFormat(diseaseName))
	}
	
	def findDiseaseUnknown(String diseaseName)
	{
		def name = Utils.importFormat(diseaseName)
		if (name==null || name.isEmpty())
		{
			name = d.UNKNOWN
		}
		
		def disease = Disease.findByDisease_Name(name)
		
	}
	
	def findOrganisms(String organismNamesLine, String organismNotes)
	{
		def Organisms = (Utils.importFormat(organismNamesLine))
		if (Organisms != null){Organisms = Organisms.split(d.tokenSemiColon)}
//		println("methods : $methods")
		def set
		if(Organisms!=null)
		{
			set = new HashSet<Organism>()
			//methodsArray = new Method[methods.length]
			for(int i = 0; i <Organisms.length;i++){
				set.add(findOrganism(Organisms[i], organismNotes))
			}
		}
		return set
	}
	
	def findOrganism(String organismName, String organismNotes)
	{
		Organism.findByOrganism_NameAndOrganism_Notes(Utils.importFormat(organismName),Utils.importFormat(organismNotes))
	}
	
	def findStructure(String iupac)
	{
		Structure.findByIupac(Utils.importFormat(iupac))
	}	
	
	def findLigandTypes(String ligandTypesLine)
	{
		def LigandTypes = (Utils.importFormat(ligandTypesLine))
		if (LigandTypes != null){LigandTypes = LigandTypes.split(d.tokenSemiColon)}
//		println("methods : $methods")
		def set
		if(LigandTypes!=null)
		{
			set = new HashSet<Ligand_Type>()
			//methodsArray = new Method[methods.length]
			for(int i = 0; i <LigandTypes.length;i++){
				set.add(findLigandType(LigandTypes[i]))
			}
		}
		return set
	}
	
	def findLigandType(String ligandTypeName)
	{
		Ligand_Type.findByLigand_Type_Name(Utils.importFormat(ligandTypeName))
	}
		
	def findGlycoconjugateType(String glycoconjugateTypeName)
	{
		Glycoconjugate_Type.findByGlycoconjugate_Type_Name(Utils.importFormat(glycoconjugateTypeName))
	}
	
	def findAglycon(String aglyconName)
	{
		if(aglyconName != null)
		{
			//println("findAglycon : " + aglyconName)
			def aglycon = Aglycon.findByAglycon_Name(Utils.importFormat(aglyconName))
			//println("foundAglycon : " + aglycon)
			return aglycon
		}
	}
		
	def findSource(String sourceName, Source_Type sourceType, Organism organism, String supplier)
	{
//		println("findSource organism : $organism")
		Source source
		source = Source.findBySource_NameAndSupplierAndOrganismAndSource_Type(sourceName, supplier, organism, sourceType)
//		println("source : $source")
		return source
	}
	
	/******************/
	
	def findAreas(String affectedAreasLine, HashSet<Organism> organisms)
	{
		HashSet<Organism> hosts = organisms
		
		if(hosts==null)
		{
			hosts= new HashSet<Organism>()
			hosts.add(d.unknownHost)
		}
		
		
		//def set = new HashSet<Area>()
		def areas = new ArrayList<Area>()
		def areaArray
		def affectedAreas 
		println("affectedAreasLine : $affectedAreasLine ")
		
		if (affectedAreasLine != null )
		{
			//the line is splitted in multiple area hierarchy
			affectedAreas = affectedAreasLine.split(d.pipe)
			println("affectedAreas : $affectedAreas")
//			areas = new String[affectedAreaLines.length]
//			println("areas : $areas ${areas.length}")
			
			for (int i = 0; i<affectedAreas.length ;i++) 
			{
				areaArray = affectedAreas[i].split(d.semicolon)
				println("areaArray : $areaArray")
				String searchedAreaName
				int reverseCounter = areaArray.size()-1; 
				while(reverseCounter > -1 && searchedAreaName == null)
				{
					def tempName=Utils.importFormat(areaArray[reverseCounter])
					if(tempName!=null && !tempName.isEmpty())
					{
						searchedAreaName = tempName 
						println("searchedAreaName : $searchedAreaName $reverseCounter" )
					}
					reverseCounter--;
				}
				
				for (Organism host : hosts)
				{				
					Area area = findArea(searchedAreaName,host)
					areas.add(area)
				}
			}
		}
		
		else
		{	
			if (organisms != null )
			{
				for (Organism organism : organisms)
				{
					Area area = findArea(d.UNKNOWN,organism)
					areas.add(area)
				}
			}	
		}
		
		 println("areas : ${areas}")	
		 return areas		
	}
	
	
	
	def findArea(String areaName, Organism organism)
	{
		def area =	Area.findByArea_NameAndOrganism(Utils.importFormat(areaName),organism)
		if(area==null)
		{
			area = Area.findByArea_NameAndOrganismIsNull(Utils.importFormat(areaName))
		}
//		println("findArea : $area")
		return area
	}
	
	/*
	def findAreas(String areaNamesLine, Organism organism)
	{
		def set = new HashSet<Area>()
		if(areaNamesLine!=null)
		{
			def areas = csvParseAffectedAreas(areaNamesLine, organism, false)//(Utils.importFormat(areaNamesLine))
		
			if (areas != null)
			{
				def area
				for (int i = 0; i<areas.length ;i++)
				{
					area = findArea(Utils.importFormat(areas[i]),organism)
					set.add(area)
				}
			}
		}	
		return set
	}
	
	def findArea(String areaName, Organism organism)
	{
		def area =	Area.findByArea_NameAndOrganism(Utils.importFormat(areaName),organism)
		if(area==null)
		{
			area = Area.findByArea_NameAndOrganismIsNull(Utils.importFormat(areaName))
		}
//		println("findArea : $area")
		return area
	}

	*/
	def findLigand(String fullName, String abbrevName, Structure structure)
	{
		def lig
//		if(fullName == null )
//		//if(fullName == null || fullName.isEmpty())
//		{
//			lig = Ligand.findByStructureAndFull_NameIsNull(structure)
//			//println("find ligand with NO name $fullName + $lig + $structure");
//		}
//		else
//		{
//			lig = Ligand.findByFull_NameAndStructure(Utils.importFormat(fullName),structure)
//			//println("find ligand with name $fullName + $lig + $structure");
//		}
            	
                if(fullName != null && !fullName.isEmpty())                
		//if(fullName == null || fullName.isEmpty())
		{
                    lig = Ligand.findByFull_NameAndStructure(Utils.importFormat(fullName),structure)
                    println("find ligand with fullName $fullName + $structure");
		}
                else if(abbrevName != null && !abbrevName.isEmpty())
                {
                    lig = Ligand.findByAbbrev_NameAndStructure(Utils.importFormat(abbrevName),structure)
                    println("find ligand with abbrevName $abbrevName + $structure");
                }
		else
		{
                    def ligands = Ligand.findAllByStructure(structure)
                    
                    for(Ligand ligand : ligands)
                    {
                      if((fullName == null || fullName.isEmpty()) && (abbrevName == null || abbrevName.isEmpty()))  
                      {
                          lig = ligand
                      }
                    }
            
//                    lig = Ligand.findByStructureAndFull_NameIsNull(structure)
                    println("find ligand with NO name $fullName + $lig + $structure");
			
		}

            return lig
	}
	
	def findDatabase(String databaseName)
	{
		Database.findByDatabase_Name(Utils.importFormat(databaseName))
	}
	
	def findBindingStrength(String bindingStrengthName)
	{
		if(bindingStrengthName!=null)
		{
			Binding_Strength.findByBinding_Strength_Name(Utils.importFormat(bindingStrengthName))
		}
	}
	
	
	def findMethods(String methodsLine)
	{
		def methods = (Utils.importFormat(methodsLine))
		if (methods != null){methods = methods.split(d.tokenSemiColon)}
//		println("methods : $methods")
		def set
		if(methods!=null)
		{
			set = new HashSet<Method>()
			//methodsArray = new Method[methods.length]
			for(int i = 0; i <methods.length;i++){
				set.add(findMethod(methods[i]))
			}
		}
		return set
	}
	
	def findMethod(String methodName)
	{
		Method.findByMethod_Name(Utils.importFormat(methodName))
	}
	
	//FIXME
//	def findBinding(Ligand ligand, Database database, Lectin lectin, String bindingNotes, Strain strain)
//	{
//		def lectin_id
//		if(lectin==null){lectin_id=null}
//		//def fimbria_id
//		//if(fimbria==null){fimbria_id=null}
//		println("Binding ligand :${ligand.id}")
//		println("Binding database :${database.id}")
//		println("Binding lectin :${lectin_id}")
//		//println("Binding fimbria :${fimbria_id}")
//		println("Binding strain :${strain.id}")
//		println("Binding bindingNotes :${bindingNotes}")
//
////		def binding = Binding.findByLigandAndDatabaseAndLectinAndFimbriaAndBinding_Notes(ligand, database, lectin, fimbria, bindingNotes)
////		Binding_Strain_Article.findByStrainAndBinding(strain, binding)
//
//		//Binding.findByLigandAndDatabaseAndLectinAndFimbriaAndBinding_Notes()
//
////		Binding.find("select b.binding_id from v_binding_strain as b"
////			+" where b.ligand_id = :ligand_id"
////			+" and b.strain_id = :strain_id"
////			+" and b.lectin_id = :lectin_id"
////			+" and b.database_id = :database_id"
////			+" and b.fimbria_id = :fimbria_id",
////			[ligand_id: ligand.id],
////			[strain_id: strain.id],
////			[lectin_id: lectin_id],
////			[database_id: database.id],
////			[fimbria_id: fimbria_id]
////			)
//		//FIXME :
///*		def dataSource
//
//		def sql = new Sql(dataSource)
//		//def rows = sql.rows("select * from v_binding_strain")
//		sql.eachRow( 'select * from v_binding_strain' ) { println "select * from v_binding_strain ${it.binding_id} -- ${it.firstName} --" }
//	*/
////		def grailsApplication
////
////			// set up the Sql object
////			def sql = groovy.sql.Sql.newInstance(
////					grailsApplication.config.grails.databaseURL,
////					config.grails.databaseUsername,
////					config.grails.databasePassword,
////					config.grails.databaseDriverClassName)
//
////		def sql = Sql.newInstance('jdbc:jtds:sqlserver://serverName/dbName-CLASS;domain=domainName', 'username',
////							   'password', 'net.sourceforge.jtds.jdbc.Driver' )
//
//	}
	
	def findArticle(String articleImportRef)
	{
		Article.findByArticle_Import_Ref(Utils.importFormat(articleImportRef)) //ARTICLE_IMPORT_REF
	}
	
	def findArticles(String articleImportRef)
	{
		def set = new HashSet<Article>()
		set.add(findArticle(articleImportRef))
		return set		
	}
	
	//NOt used
	def findBinding(Lectin lectin, Ligand ligand)
	{
		def binding = Binding.findByLectinAndLigand(lectin, ligand)
		return binding
	}
	
	def findBinding(Lectin lectin, Ligand ligand, Article article)
	{
		def bindings = Binding.findAllByLectinAndLigand(lectin, ligand)
		
		for(Binding binding : bindings)
		{
//			println("!!!binding : " + binding)
			for(Article a in binding.articles)
			{
				if(a.article_Import_Ref == article.article_Import_Ref)
				{
					return binding
				}
			}
		}
	}
}
